Skip to content

test(ledger): cover a subaccount-qualified ICRC-2 self-spend - #11139

Open
mbjorkqvist wants to merge 3 commits into
masterfrom
mathias/DEFI-2978-icrc2-self-spend-subaccount
Open

test(ledger): cover a subaccount-qualified ICRC-2 self-spend#11139
mbjorkqvist wants to merge 3 commits into
masterfrom
mathias/DEFI-2978-icrc2-self-spend-subaccount

Conversation

@mbjorkqvist

@mbjorkqvist mbjorkqvist commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

DEFI-2978

Why

A transfer_from needs no allowance only when the spender is the account it spends from, and the ledger decides that on the whole account, not the owner alone. The state machine suite covered this for the default subaccount only (test_transfer_from_self, whose args hardcode spender_subaccount: None), so nothing pinned either half of the subaccount case: that naming the account's own subaccount succeeds, and that naming none fails for want of an allowance even though the owner matches.

Callers depend on the rule — the ckETH minter burns from its own fee subaccount — so a regression in it should surface in the ledger's own suite rather than in a consumer's integration test.

What

One generic test in the shared suite, wired into the ICP and ICRC ledgers the same way test_transfer_from_self is, so both get it. The successful spend is asserted to land at block index 1, which also shows the rejected attempt wrote no block.

Verified against ledger_test, ledger_test_u256 and the ICP ledger_canister_test.

A spend needs no allowance only when the spender is the account it spends
from, and the ledger decides that on the whole account rather than the owner
alone. The suite covered this only for the default subaccount, so neither
half of the subaccount case was pinned: that naming the account's own
subaccount succeeds, and that naming none fails for want of an allowance
even though the owner matches.

Callers rely on the rule — the ckETH minter burns from its own fee
subaccount — so a regression should surface here rather than in a consumer's
integration test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a shared state-machine regression test to ensure ICRC-2 transfer_from correctly treats “self-spend without allowance” as equality on the full account (owner + subaccount), not just on the owner principal. This protects callers that burn/spend from their own non-default subaccounts (e.g., fee subaccounts) by catching regressions in the ledger’s own test suite.

Changes:

  • Introduce test_transfer_from_self_subaccount to verify (a) missing spender subaccount fails with InsufficientAllowance and writes no block, and (b) specifying the matching subaccount succeeds without allowance.
  • Wire the new shared test into both the ICRC-1 ledger test suite and the ICP ledger test suite.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
rs/ledger_suite/tests/sm-tests/src/lib.rs Adds the shared state-machine test covering subaccount-qualified ICRC-2 self-spend behavior and block index expectations.
rs/ledger_suite/icrc1/ledger/tests/tests.rs Registers the new shared test in the ICRC-1 ledger test harness.
rs/ledger_suite/icp/ledger/tests/tests.rs Registers the new shared test in the ICP ledger test harness.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

mbjorkqvist and others added 2 commits August 14, 2026 07:23
…dgers

Burning is how an account holding tokens under a subaccount gives them up,
and it is a self-spend when the spender names that same subaccount, so the
ledger charges no fee and reduces the supply.

Kept separate from the allowance test and wired into the ICRC ledgers only:
the ICP ledger checks an allowance for a burn even when the spender is the
account itself, although it exempts that case when consuming one, so the same
call fails there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two ledgers disagree, so the shared test returns the outcome and each
caller states what its own ledger owes: an ICRC ledger accepts the burn, the
ICP ledger rejects it for want of an allowance it would never have consumed.

Characterising the ICP behaviour beats omitting it. The rejected path is now
asserted to leave balance and supply untouched, and closing the gap in
Operation::Burn has to flip this assertion rather than pass unnoticed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mbjorkqvist
mbjorkqvist marked this pull request as ready for review August 14, 2026 08:47
@mbjorkqvist
mbjorkqvist requested a review from a team as a code owner August 14, 2026 08:47
@github-actions github-actions Bot added the @defi label Aug 14, 2026

@gregorydemay gregorydemay left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mbjorkqvist !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants